# Define here the models for your spider middleware
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/spider-middleware.html
import logging
import time

from scrapy import signals

# useful for handling different item types with a single interface
from itemadapter import is_item, ItemAdapter


class MiddleSpiderMiddleware:
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the spider middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_spider_input(self, response, spider):
        # Called for each response that goes through the spider
        # middleware and into the spider.

        # Should return None or raise an exception.
        return None

    def process_spider_output(self, response, result, spider):
        # Called with the results returned from the Spider, after
        # it has processed the response.

        # Must return an iterable of Request, or item objects.
        for i in result:
            yield i

    def process_spider_exception(self, response, exception, spider):
        # Called when a spider or process_spider_input() method
        # (from other spider middleware) raises an exception.

        # Should return either None or an iterable of Request or item objects.
        pass

    def process_start_requests(self, start_requests, spider):
        # Called with the start requests of the spider, and works
        # similarly to the process_spider_output() method, except
        # that it doesn’t have a response associated.

        # Must return only requests (not items).
        for r in start_requests:
            yield r

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)


class MiddleDownloaderMiddleware:
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
        # Called for each request that goes through the downloader
        # middleware.

        # Must either:
        # - return None: continue processing this request
        # - or return a Response object
        # - or return a Request object
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
        return None

    def process_response(self, request, response, spider):
        # Called with the response returned from the downloader.

        # Must either;
        # - return a Response object
        # - return a Request object
        # - or raise IgnoreRequest
        return response

    def process_exception(self, request, exception, spider):
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.

        # Must either:
        # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain
        # - return a Request object: stops process_exception() chain
        pass

    def spider_opened(self, spider):
        spider.logger.info('Spider opened  你好啊: %s' % spider.name)



import random
class FakeChromeUA:
    first_num = random.randint(55, 62)
    third_num = random.randint(0, 3200)
    fourth_num = random.randint(0, 140)
    os_type = [
                '(Windows NT 6.1; WOW64)', '(Windows NT 10.0; WOW64)', '(X11; Linux x86_64)','(Macintosh; Intel Mac OS X 10_12_6)'
               ]

    chrome_version = 'Chrome/{}.0.{}.{}'.format(first_num, third_num, fourth_num)

    @classmethod
    def get_ua(cls):
        return ' '.join(['Mozilla/5.0', random.choice(cls.os_type), 'AppleWebKit/537.36','(KHTML, like Gecko)', cls.chrome_version, 'Safari/537.36'])

# 自定义用户代理中间件
class RandomUserAgent:

    def __init__(self):
        self.user_agent = FakeChromeUA.get_ua()

    def process_request(self, request, spider):
        if self.user_agent:
            # print('我看有没有触发成功')
            # request.headers.setdefault(b'User-Agent', self.user_agent)
            request.headers['User-Agent'] = self.user_agent


class RandomDelayMiddleware(object):
    def __init__(self, delay):
        self.delay = delay

    @classmethod
    def from_crawler(cls, crawler):
        delay = crawler.spider.settings.get("RANDOM_DELAY", 1)
        if not isinstance(delay, int):
            raise ValueError("RANDOM_DELAY need a int")
        return cls(delay)

    def process_request(self, request, spider):
        # delay = random.randint(0, self.delay)
        # print(request.url,'我是地址')
        delay = random.uniform(0, self.delay)
        delay = float("%.1f" % delay)
        logging.debug("### random delay: %s s ###" % delay)
        time.sleep(delay)


from selenium import webdriver
from scrapy.http import HtmlResponse
class SeleniumMiddle:
    def __init__(self):
        self.browser = webdriver.Chrome()
        self.timeout = random.randint(1,3)
        self.browser.set_page_load_timeout(self.timeout)

    def process_request(self, request, spider):
        logging.debug("selenium开启对 %s  " % spider.name )
        self.browser.get(request.url)
        html = self.browser.page_source
        return HtmlResponse(url=request.url,body=html,request=request,encoding='utf-8',status=200)

    def __del__(self):
        self.browser.close()


from pyppeteer import launch
import asyncio
# 异步机制
class PyputeerMiddle:
    def process_request(self, request, spider):
        page = asyncio.get_event_loop().run_until_complete(self.main(request.url))
        return HtmlResponse(url=request.url, body=page, request=request, encoding='utf-8', status=200)

    async def main(self,url):
        logging.debug("pyppeteer开启对 %s  " % url)
        browser = await launch()
        page = await browser.newPage()
        await page.goto(url)
        text  =await page.content()
        return text




